﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Mime;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using HtmlAgilityPack;

namespace EntityModule
{
    class ShackPost
    {
        public string Body { get; set; }
        public string Preview { get; set; }
        public string Date { get; set; }
        public string Author { get; set; }
        public string Category { get; set; }
        public string Last_reply_id { get; set; }
        public string ReplyCount { get; set; }
        public string Id { get; set; }
    }
    public static class HtmlHelper
    {
        public static string Replace(string input, string[] tags)
        {
            try
            {
                string _newString = input;
                foreach (string removeElement in tags)
                {
                    while (_newString.ToLower().Contains("<" + removeElement.ToLower()))
                    {
                        _newString = _newString.Substring(0, _newString.ToLower().IndexOf("<" + removeElement.ToLower())) + _newString.Substring(_newString.ToLower().IndexOf("</" + removeElement.ToLower() + ">") + removeElement.Length + 3);
                    }
                }
                return _newString;
            }
            catch (Exception)
            {
                return input;
            }
        }
        public static string RemoveTag(this string input, string tags)
        {
            try
            {
                string _newString = input;
                string removeElement = tags;
                while (_newString.ToLower().Contains("<" + removeElement.ToLower()))
                {
                    _newString = _newString.Substring(0, _newString.ToLower().IndexOf("<" + removeElement.ToLower())) + _newString.Substring(_newString.ToLower().IndexOf("</" + removeElement.ToLower() + ">") + removeElement.Length + 3);
                }
                return _newString;
            }
            catch (Exception)
            {
                return input;
            }
        }
        public static string GetInnerHtmlTag(this string input, string tag)
        {
            try
            {
                HtmlDocument htmldoc = new HtmlDocument();
                htmldoc.LoadHtml(input);
                return htmldoc.DocumentNode.SelectSingleNode("//" + tag).InnerHtml;
            }
            catch
            {
            }
            return input;
        }
        public static string SetStyleTag(this string input, string tag, string style)
        {
            try
            {
                HtmlDocument htmldoc = new HtmlDocument();
                htmldoc.LoadHtml(input);
                var divs = htmldoc.DocumentNode.SelectNodes("//" + tag);
                foreach (HtmlNode htmlNode in divs)
                {
                    if (!htmlNode.Attributes.Contains("style"))
                        htmlNode.Attributes.Add("style", style);
                    else htmlNode.Attributes["style"].Value = style;
                }
                return htmldoc.DocumentNode.InnerHtml;
            }
            catch
            {
            }
            return string.Empty;
        }
        public static string SetStyleTag(this string input, string tagName, string classCss, string style)
        {
            try
            {
                HtmlDocument htmldoc = new HtmlDocument();
                htmldoc.LoadHtml(input);
                var divs = htmldoc.DocumentNode.SelectNodes("//" + tagName);
                foreach (HtmlNode tag in divs)
                {
                    if (tag.Attributes["class"] != null && string.Compare(tag.Attributes["class"].Value, classCss, StringComparison.InvariantCultureIgnoreCase) == 0)
                    {
                        if (!tag.Attributes.Contains("style"))
                            tag.Attributes.Add("style", style);
                        else tag.Attributes["style"].Value = style;
                    }
                }
                return htmldoc.DocumentNode.InnerHtml;
            }
            catch
            {
            }
            return input;
        }
        public static string GetInnerHtmlDivStr(string strClass, string html)
        {
            try
            {
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(html);
                return doc.DocumentNode.SelectSingleNode("//div[starts-with(@class,'" + strClass + "')]").InnerHtml;
            }
            catch
            {
            }
            return html;
        }
        public static string RemoveTagClss(string tagName, string clss, string html)
        {
            HtmlDocument htmldoc = new HtmlDocument();
            htmldoc.LoadHtml(html);
            var divs = htmldoc.DocumentNode.SelectNodes("//" + tagName);
            if (divs != null)
            {
                foreach (var tag in divs)
                {
                    if (tag.Attributes["class"] != null && string.Compare(tag.Attributes["class"].Value, clss, StringComparison.InvariantCultureIgnoreCase) == 0)
                    {
                        tag.Remove();
                    }
                }
            }
            return htmldoc.DocumentNode.InnerHtml;
        }
        public static string RemoveTagID(string tagName, string tagId, string html)
        {
            HtmlDocument htmldoc = new HtmlDocument();
            htmldoc.LoadHtml(html);
            var divs = htmldoc.DocumentNode.SelectNodes("//" + tagName);
            if (divs != null)
            {
                foreach (var tag in divs)
                {
                    if (tag.Attributes["id"] != null && string.Compare(tag.Attributes["id"].Value, tagId, StringComparison.InvariantCultureIgnoreCase) == 0)
                    {
                        tag.Remove();
                    }
                }
            }
            return htmldoc.DocumentNode.InnerHtml;
        }
        public static string GetInnerHtmlDiv(string strClass, string url)
        {
            try
            {
                WebClient client = new WebClient();
                client.Encoding = Encoding.UTF8;
                String shackHTML = client.DownloadString(url);
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(shackHTML);
                string title = doc.DocumentNode.SelectSingleNode("//div[starts-with(@class,'" + strClass + "')]").InnerHtml;
                return Replace(title, new string[] { "a", "script" });
            }
            catch
            {
            }
            return string.Empty;


            /* // get the number of pages for this story
             HtmlNodeCollection pages = doc.DocumentNode.SelectNodes("//a[starts-with(@href,'/laryn.x?story=')]");
             if (pages != null && pages.Count > 1)
                 totalPages = pages[pages.Count - 2].InnerText.ToString();
             else
                 totalPages = "1";

             // get the story
             storyID = doc.DocumentNode.SelectSingleNode("//input[@id='p_group']").GetAttributeValue("value", "");



             foreach (HtmlNode post in doc.DocumentNode.SelectNodes("//li[starts-with(@id,'item_')]"))
             {
                 ParsePost(post.InnerHtml);
             }

             ServePageAsXML();*/

        }
        /*    protected void ParsePost(String node)
            {
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(node);

                ShackPost sp = new ShackPost();


                sp.Body = "";// doc.DocumentNode.SelectSingleNode("//div[@class='postbody']").InnerHtml.Replace("\r", "&#13;").Replace("\n", "").Replace("<br>", "<br />");

                string preview = doc.DocumentNode.SelectSingleNode("//span[@class='oneline_body']").InnerHtml.Replace("\r\n", " ").Trim();
                preview = Regex.Replace(preview, "<span class=\"jt_spoiler\" onclick=\".*?\">(.*?)</span>", "_________");
                preview = Regex.Replace(preview, @"<(.|\n)*?>", "");
                preview = Regex.Replace(preview, "(\r\n|\r|\n|\n\r)", "");
                sp.Preview = preview;

                //sp.Preview = doc.DocumentNode.SelectSingleNode("//span[@class='oneline_body']").InnerText.Replace("\r\n", " ").Trim();
                sp.Date = "";// doc.DocumentNode.SelectSingleNode("//div[@class='postdate']").InnerText.Trim();
                sp.Author = doc.DocumentNode.SelectSingleNode("//div[starts-with(@class,'fck_detail')]").InnerText;

                string modmarker;
                int beginpos;
                int endpos;
                string post;
                String[] split;

                // first post is different.. horray for HTML!
                if (doc.DocumentNode.SelectSingleNode("//div[starts-with(@class,'fullpost ')]") != null)
                {
                    modmarker = doc.DocumentNode.SelectSingleNode("//div[starts-with(@class,'fullpost ')]").GetAttributeValue("class", "").ToString();
                    modmarker = modmarker.Substring(15);
                    modmarker = modmarker.Substring(0, modmarker.IndexOf(" "));
                    sp.Category = modmarker;

                    // get last postid
                    beginpos = node.LastIndexOf("return clickItem( ") + 18;
                    endpos = node.IndexOf(" );", beginpos);
                    post = node.Substring(beginpos, endpos - beginpos);
                    split = Regex.Split(post, ", ");
                    sp.Last_reply_id = split[1];


                }
                else
                {
                    modmarker = doc.DocumentNode.SelectSingleNode("//div[starts-with(@class,'oneline ')]").GetAttributeValue("class", "").ToString();
                    modmarker = modmarker.Substring(modmarker.IndexOf("olmod_") + 6);
                    modmarker = modmarker.Substring(0, modmarker.IndexOf(" "));
                    sp.Category = modmarker;
                }

                // get postid's
                beginpos = node.IndexOf("return clickItem( ") + 18;
                endpos = node.IndexOf(" );", beginpos);
                post = node.Substring(beginpos, endpos - beginpos);
                split = Regex.Split(post, ", ");

                sp.Id = split[1];


                // all the posts that reply to this are also in this node string, so we count them for the reply count
                HtmlNodeCollection replies = doc.DocumentNode.SelectNodes("//li[starts-with(@id,'item_')]");
                if (replies != null)
                    sp.ReplyCount = replies.Count.ToString();
                else
                    sp.ReplyCount = "0";

                posts.Add(sp);

                GetFullPost();

            }
            private void GetFullPost()
            {

                String rootid = posts[0].Id;
                String id = posts[posts.Count - 1].Id;
                String fullPostText = "";
                String postDate = "";

                if (MediaTypeNames.Application["PostCache"] != null)
                    postsHash = (Hashtable)MediaTypeNames.Application["PostCache"];


                if (postsHash[id] == null)
                {
                    String url = String.Format("http://www.shacknews.com/frame_laryn.x?root={0}&id={1}", rootid, id);

                    System.Net.WebClient client = new WebClient();
                    String shackHTML = client.DownloadString(url);

                    HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
                    doc.LoadHtml(shackHTML);

                    fullPostText = doc.DocumentNode.SelectSingleNode("//div[@class='postbody']").InnerHtml.Replace("\r", "&#13;").Replace("\n", "").Replace("<br>", "<br />");
                    postDate = doc.DocumentNode.SelectSingleNode("//div[@class='postdate']").InnerText.Trim();

                    // TODO: I don't like the user of the HastTable in this way.. going to an array list everytime seems heavy to me
                    // Maybe mix a Stack + HashTable
                    if (postsHash.Count > cacheMax)
                    {
                        ArrayList keys = new ArrayList(postsHash.Keys);
                        string removeString = keys[0].ToString();
                        postsHash.Remove(removeString);
                    }

                    // TODO: since we're using a hashtable we append the post date and text... ug...
                    postsHash.Add(id, postDate + "*" + fullPostText);
                    Application["PostCache"] = postsHash;

                }
                else
                {

                    String postInfo = postsHash[id].ToString();

                    // TODO: since we're using a hashtable we append the post date and text... ug...
                    int breakloc = postInfo.IndexOf("*");
                    postDate = postInfo.Substring(0, breakloc);
                    fullPostText = postInfo.Substring(breakloc + 1);// +" [ cached ]";


                }

                posts[posts.Count - 1].Body = fullPostText.Replace("return doSpoiler( event );", "this.className = '';");
                posts[posts.Count - 1].Date = postDate;



            }

            private void ServePageAsXML()
            {

                /*Response.ContentType = "text/xml";

                Encoding utf8 = new UTF8Encoding(false);


                XmlTextWriter writer = new XmlTextWriter(Response.OutputStream, utf8);
                writer.Formatting = System.Xml.Formatting.Indented;

                writer.WriteStartDocument();
                writer.WriteStartElement("comments");

                writer.WriteAttributeString("story_name", this.title);
                writer.WriteAttributeString("last_page", this.totalPages);
                writer.WriteAttributeString("page", this.currentPage);
                writer.WriteAttributeString("story_id", this.storyID);

                List<int> threading = new List<int>();

                foreach (var item in posts)
                {


                    writer.WriteStartElement("comment");
                    writer.WriteAttributeString("reply_count", item.ReplyCount);
                    writer.WriteAttributeString("date", item.Date);
                    writer.WriteAttributeString("category", item.Category);
                    writer.WriteAttributeString("author", item.Author);
                    writer.WriteAttributeString("id", item.Id);

                    if (item.Last_reply_id != null && item.Last_reply_id.Length > 0)
                        writer.WriteAttributeString("last_reply_id", item.Last_reply_id); // no last reply on thread view

                    writer.WriteAttributeString("preview", item.Preview);  // squeegy's api does the actual truncate off a clean body, we don't
                    writer.WriteElementString("body", item.Body);

                    // add a blank comment tag if no comments
                    if (int.Parse(item.ReplyCount) == 0)
                    {
                        writer.WriteStartElement("comments");
                        writer.WriteFullEndElement();
                        writer.WriteEndElement();
                    }

                    // close the tags that have since had the proper number of replies go by
                    for (int i = 0; i < threading.Count; i++)
                    {
                        threading[i]--;
                        if (threading[i] == 0)
                        {
                            writer.WriteFullEndElement();
                            writer.WriteEndElement();
                        }
                    }


                    if (int.Parse(item.ReplyCount) > 0)
                    {
                        writer.WriteStartElement("comments");
                        threading.Insert(0, int.Parse(item.ReplyCount));
                    }


                }

                writer.WriteEndElement();
                writer.WriteEndDocument();

                writer.Flush();#1#


            }*/
    }
}
